import os
import sys
import fitz  # PyMuPDF
from docx import Document
from docx.shared import Cm
from PIL import Image
import io
from datetime import datetime


# 全局变量集中管理
class GlobalConfig:
    # 文档配置参数
    DEFAULT_DPI = 72  # 降低DPI提升速度
    A4_MARGIN = 1.5
    A4_WIDTH = 21
    A4_HEIGHT = 29.7
    A4_MAX_WIDTH = A4_WIDTH - 2 * A4_MARGIN  # 有效宽度
    A4_MAX_HEIGHT = A4_HEIGHT - 2 * A4_MARGIN  # 有效高度

    # 路径与状态变量
    root_dir = ""
    output_dir = ""
    logger = None
    doc = None  # 全局文档对象


def init_global_vars(args: list) -> None:
    """初始化所有全局变量，集中处理配置逻辑"""
    # 解析路径参数
    GlobalConfig.root_dir = args[0]
    GlobalConfig.output_dir = args[1]
    os.makedirs(GlobalConfig.output_dir, exist_ok=True)

    # 初始化日志
    log_file = os.path.join(GlobalConfig.output_dir, "generate_log.txt")
    GlobalConfig.logger = Logger(log_file)

    # 初始化文档对象
    doc = Document()
    section = doc.sections[0]
    section.orientation = 0  # 纵向
    section.page_width = Cm(GlobalConfig.A4_WIDTH)
    section.page_height = Cm(GlobalConfig.A4_HEIGHT)
    section.top_margin = Cm(GlobalConfig.A4_MARGIN)
    section.bottom_margin = Cm(GlobalConfig.A4_MARGIN)
    section.left_margin = Cm(GlobalConfig.A4_MARGIN)
    section.right_margin = Cm(GlobalConfig.A4_MARGIN)
    doc.add_heading("业绩情况证明文件", 0)
    doc.add_paragraph(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    doc.add_paragraph(f"来源目录: {GlobalConfig.root_dir}")
    GlobalConfig.doc = doc

    # 打印初始化信息
    logger = GlobalConfig.logger
    logger.print("=" * 50)
    logger.print("          业绩情况证明文件生成程序          ")
    logger.print(f"处理根目录：{GlobalConfig.root_dir}")
    logger.print(f"输出目录：{GlobalConfig.output_dir}")
    logger.print(f"A4配置：宽{GlobalConfig.A4_WIDTH}cm × 高{GlobalConfig.A4_HEIGHT}cm，边距{GlobalConfig.A4_MARGIN}cm")
    logger.print(f"渲染DPI：{GlobalConfig.DEFAULT_DPI}（降低以提升速度）")
    logger.print("=" * 50)

    # 验证输入目录
    if not os.path.exists(GlobalConfig.root_dir):
        logger.print(f"错误：输入目录不存在！{GlobalConfig.root_dir}")
        sys.exit(1)


class Logger:
    """日志工具类，同时输出到控制台和文件"""

    def __init__(self, log_file_path):
        log_dir = os.path.dirname(log_file_path)
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        self.log_file = log_file_path

    def print(self, message):
        """打印并写入日志"""
        print(message)
        with open(self.log_file, 'a', encoding='utf-8') as f:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            f.write(f"[{timestamp}] {message}\n")


def convert_pdf_to_images(pdf_path, quality=60):
    """优化：降低图片质量，使用全局变量减少参数传递"""
    logger = GlobalConfig.logger
    logger.print(f"开始转换PDF：{os.path.basename(pdf_path)}")
    images = []  # 存储内存流

    try:
        doc = fitz.open(pdf_path)
        logger.print(f"PDF包含 {len(doc)} 页，按 {GlobalConfig.DEFAULT_DPI} DPI 渲染")
        zoom = GlobalConfig.DEFAULT_DPI / 72.0  # 基于全局DPI计算缩放
        mat = fitz.Matrix(zoom, zoom)

        for page_num in range(len(doc)):
            try:
                page = doc.load_page(page_num)
                pix = page.get_pixmap(matrix=mat, alpha=False, colorspace=fitz.csRGB)
                img_bytes = pix.tobytes("png")  # 生成PNG字节流

                if img_bytes:
                    images.append(io.BytesIO(img_bytes))  # 存储内存流
                    logger.print(f"PDF页 {page_num + 1}/{len(doc)} 转换成功")
                else:
                    logger.print(f"PDF页 {page_num + 1}/{len(doc)} 生成失败（内容为空）")
            except Exception as e:
                logger.print(f"PDF页 {page_num + 1}/{len(doc)} 处理失败：{str(e)}，跳过该页")
                continue

        doc.close()
        logger.print(f"PDF转换完成，共生成 {len(images)} 张有效图片")
        return images
    except Exception as e:
        logger.print(f"PDF文件整体处理失败：{str(e)}，跳过该PDF")
        return []


def insert_image_fit_a4_portrait(img_stream):
    """优化：直接使用全局文档和配置，消除冗余参数"""
    logger = GlobalConfig.logger
    doc = GlobalConfig.doc
    a4_max_width = GlobalConfig.A4_MAX_WIDTH
    a4_max_height = GlobalConfig.A4_MAX_HEIGHT

    try:
        with Image.open(img_stream) as img:
            width_px, height_px = img.size
            # 像素转厘米（1cm ≈ 37.795像素）
            width_cm = width_px / 37.795
            height_cm = height_px / 37.795

            # 计算缩放比例（保持原图比例）
            scale_width = a4_max_width / width_cm if width_cm > a4_max_width else 1.0
            scale_height = a4_max_height / height_cm if height_cm > a4_max_height else 1.0
            scale = min(scale_width, scale_height)
            new_width_cm = width_cm * scale
            new_height_cm = height_cm * scale

            # 重置流指针并插入图片
            img_stream.seek(0)
            doc.add_picture(img_stream, width=Cm(new_width_cm), height=Cm(new_height_cm))

        logger.print("图片插入成功")
        return True
    except Exception as e:
        logger.print(f"图片插入失败，错误：{str(e)}，跳过该图片")
        return False


def process_directory(directory, level=1):
    """递归处理目录及其子目录中的所有PDF文件"""
    logger = GlobalConfig.logger
    doc = GlobalConfig.doc
    dir_name = os.path.basename(directory)

    logger.print(f"\n{'=' * 20} 开始处理目录：{dir_name}（层级：{level}）{'=' * 20}")

    # 添加目录标题到Word文档
    doc.add_heading(dir_name, level=level)

    # 统计目录中的文件和子目录
    items = os.listdir(directory)
    files = [item for item in items if os.path.isfile(os.path.join(directory, item))]
    subdirs = [item for item in items if os.path.isdir(os.path.join(directory, item))]

    logger.print(f"目录包含 {len(files)} 个文件和 {len(subdirs)} 个子目录")

    # 处理当前目录中的PDF文件
    pdf_files = [f for f in files if f.lower().endswith('.pdf')]
    if pdf_files:
        logger.print(f"发现 {len(pdf_files)} 个PDF文件，开始处理")
        for pdf_file in pdf_files:
            pdf_path = os.path.join(directory, pdf_file)
            logger.print(f"\n处理PDF文件：{pdf_file}")
            doc.add_paragraph(f"文件名: {pdf_file}")

            # 转换并插入PDF内容
            pdf_images = convert_pdf_to_images(pdf_path)
            for img_idx, img_stream in enumerate(pdf_images, 1):
                logger.print(f"插入PDF第 {img_idx}/{len(pdf_images)} 页")
                insert_image_fit_a4_portrait(img_stream)

    # 递归处理子目录
    for subdir in subdirs:
        subdir_path = os.path.join(directory, subdir)
        logger.print(f"\n发现子目录：{subdir}，递归处理")
        process_directory(subdir_path, level + 1)

    logger.print(f"{'=' * 20} 目录 {dir_name} 处理完成 {'=' * 20}")


def save_with_retry(original_path, max_attempts=5):
    """保存文档，处理文件占用问题"""
    logger = GlobalConfig.logger
    doc = GlobalConfig.doc
    dir_name = os.path.dirname(original_path)
    base_name = os.path.basename(original_path)
    file_name, ext = os.path.splitext(base_name)

    for i in range(max_attempts):
        try:
            save_path = original_path if i == 0 else os.path.join(dir_name, f"{file_name}_{i}{ext}")
            doc.save(save_path)
            logger.print(f"文档保存成功！路径：{save_path}")
            return save_path
        except PermissionError:
            logger.print(f"保存失败：文件被占用（{save_path}），尝试第 {i + 1} 次")
        except Exception as e:
            logger.print(f"保存失败：{str(e)}（{save_path}），尝试第 {i + 1} 次")

    logger.print(f"达到最大尝试次数（{max_attempts}次），保存失败")
    return None


def main():
    # 验证参数
    args = sys.argv[1:]
    if len(args) < 2:
        print("用法：python script.py <输入目录> <输出目录>")
        sys.exit(1)

    # 初始化全局配置
    init_global_vars(args)
    logger = GlobalConfig.logger

    # 处理根目录
    logger.print(f"开始处理根目录：{GlobalConfig.root_dir}")
    process_directory(GlobalConfig.root_dir, level=1)

    # 保存最终文档
    original_output = os.path.join(GlobalConfig.output_dir, "业绩情况证明文件.docx")
    logger.print("\n开始保存文档...")
    save_with_retry(original_output)

    logger.print("\n" + "#" * 50)
    logger.print("处理全部完成！")
    logger.print("#" * 50)


if __name__ == "__main__":
    main()